import java.util.*;
import java.util.stream.Stream;

/**
 * 使用Stream流的方式,遍历集合,对集合中的数据进行过滤
 * Stream流是JDK1.8之后出现的,关注的是做什么,而不是怎么做
 */
public class Demo01Stream {
    public static void main(String[] args) {
        //创建一个List集合,存储姓名
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");

        //基本演示
        list.stream()
                .filter(name -> name.startsWith("张"))  //filter()过滤
                .filter(name -> name.length() == 3)
                .forEach(name -> System.out.println(name)); //forEach()遍历

//        demo1();  //集合,数组转换成Stream
//        demo2();  //forEach()方法,遍历流输出,<终结方法>
//        demo3();  //filter()方法,数据进行过滤<可继续调用方法>
//        demo4();  //map()方法,用于类型转换<可继续调用方法>
//        demo5();  //Stream.concat()静态方法,合并流<可继续调用方法>
//        demo6();  //limit(long maxSize)方法,可以对流进行截取,只取用前n个。<可继续调用方法>
//        demo7();  //skip(long n)方法,用于跳过元素,跳过前几个元素;<可继续调用方法>
//        demo8();   //count()方法,用于统计Stream流中元素的个数,<终结方法>
    }

    /**
     * count()方法.用于统计Stream流中元素的个数
     *      是一个终结方法,遍历之后就不能继续调用Stream流中的其他方法
     */
    private static void demo8() {
        //获取一个Stream流
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
        list.add(7);
        Stream<Integer> stream = list.stream();
        long count = stream.count();
        System.out.println(count);//7
    }

    /**
     * skip方法用于跳过跳过元素
     * 如果流的当前长度大于n，则跳过前n个；否则将会得到一个长度为0的空流。
     *      返回的是一个新的流,所以可以继续调用Stream流中的其他方法
     */
    private static void demo7() {
        //获取一个Stream流
        String[] arr = {"美羊羊","喜洋洋","懒洋洋","灰太狼","红太狼"};
        Stream<String> stream = Stream.of(arr);
        //使用skip方法跳过前3个元素
        Stream<String> stream2 = stream.skip(3);
        //遍历stream2流
        stream2.forEach(name-> System.out.println(name));
    }

    /**
     * limit方法是一个延迟方法,只是对流中的元素进行截取,
     *      返回的是一个新的流,所以可以继续调用Stream流中的其他方法
     */
    private static void demo6() {
        //获取一个Stream流
        String[] arr = {"美羊羊","喜洋洋","懒洋洋","灰太狼","红太狼"};
        Stream<String> stream = Stream.of(arr);
        //使用limit对Stream流中的元素进行截取,只要前3个元素
        Stream<String> stream2 = stream.limit(3);
        //遍历stream2流
        stream2.forEach(name-> System.out.println(name));
    }

    /**
     * Stream接口的静态方法concat,用于把流组合到一起
     *      返回的是一个新的流,所以可以继续调用Stream流中的其他方法
     */
    private static void demo5() {
        //创建一个Stream流
        Stream<String> stream1 = Stream.of("张三丰", "张翠山", "赵敏", "周芷若", "张无忌");
        //获取一个Stream流
        String[] arr = {"美羊羊","喜洋洋","懒洋洋","灰太狼","红太狼"};
        Stream<String> stream2 = Stream.of(arr);
        //把以上两个流组合为一个流
        Stream<String> concat = Stream.concat(stream1, stream2);
        //遍历concat流
        concat.forEach(name-> System.out.println(name));
    }

    /**
     * map()方法,常用于类型转换
     *      返回的是一个新的流,所以可以继续调用Stream流中的其他方法
     */
    private static void demo4() {
        //获取一个String类型的Stream流
        Stream<String> stream = Stream.of("1", "2", "3", "4");
        //使用map方法,把字符串类型的整数,转换(映射)为Integer类型的整数
        Stream<Integer> stream2 = stream.map((String s)-> Integer.parseInt(s));
        //遍历Stream2流
        stream2.forEach(i-> System.out.println(i));
    }

    /**
     * filter()方法,过滤器
     *      返回的是一个新的流,所以可以继续调用Stream流中的其他方法
     */
    private static void demo3() {
        //创建一个Stream流
        Stream<String> stream = Stream.of("张三丰", "张翠山", "赵敏", "周芷若", "张无忌");
        //对Stream流中的元素进行过滤,只要姓张的人
        Stream<String> stream2 = stream.filter((String name)-> name.startsWith("张"));
        //遍历stream2流
        stream2.forEach(name-> System.out.println(name));
        /*
            Stream流属于管道流,只能被消费(使用)一次
            第一个Stream流调用完毕方法,数据就会流转到下一个Stream上
            而这时第一个Stream流已经使用完毕,就会关闭了
            所以第一个Stream流就不能再调用方法了
            IllegalStateException: stream has already been operated upon or closed
         */
        //遍历stream流
        stream.forEach(name-> System.out.println(name));
    }

    /**
     * forEach方法,用来遍历流中的数据
     *      是一个终结方法,遍历之后就不能继续调用Stream流中的其他方法
     */
    private static void demo2() {
        //获取一个Stream流
        Stream<String> stream = Stream.of("张三", "李四", "王五", "赵六", "田七");
        //使用Stream流中的方法forEach对Stream流中的数据进行遍历
        /*stream.forEach((String name)->{
            System.out.println(name);
        });*/
        stream.forEach(name->System.out.println(name));
    }

    /**
     * 集合及数组转换成Stream流
     *  获取一个流非常简单，有以下几种常用的方式：
     *
     *      - 所有的Collection集合都可以通过stream默认方法获取流；
     *          default Stream<E> stream()
     *
     *      - Stream接口的静态方法of可以获取数组对应的流。
     *          static <T> Stream<T> of(T... values)
     *
     *      - 参数是一个可变参数,那么我们就可以传递一个数组
     */
    private static void demo1() {
        //List集合>Stream流
        List<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();
        //Set集合>Stream
        Set<String> set = new HashSet<>();
        Stream<String> stream2 = set.stream();

        //Map集合>Stream
        Map<String,String> map = new HashMap<>();
        //获取键,存储到一个Set集合中
        Set<String> keySet = map.keySet();
        Stream<String> stream3 = keySet.stream();

        //获取值,存储到一个Collection集合中
        Collection<String> values = map.values();
        Stream<String> stream4 = values.stream();

        //获取键值对(键与值的映射关系 entrySet)
        Set<Map.Entry<String, String>> entries = map.entrySet();
        Stream<Map.Entry<String, String>> stream5 = entries.stream();

        //可变参数>Stream流
        Stream<Integer> stream6 = Stream.of(1, 2, 3, 4, 5);
        //数组>Stream流
        Integer[] arr = {1,2,3,4,5};
        Stream<Integer> stream7 = Stream.of(arr);
        String[] arr2 = {"a","bb","ccc"};
        Stream<String> stream8 = Stream.of(arr2);
    }
}
